<?php
namespace App\Services\Activity;

use App\Enums\ActivityEnum;
use App\Exceptions\BasicException;
use App\Models\ActivityDB\Gift2022NewUserRewardLog;
use App\Models\MainDB\Coin;
use App\Models\MainDB\MallProducts;
use App\Repositories\Activity\NewUserGiftRepository;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Throwable as ThrowableAlias;

class NewUserGiftRewardService
{
    /**
     * @throws BasicException
     */
    private function beforeReceive(int $userId): Collection
    {
        $repo = new NewUserGiftRepository();
        $tasks = $repo->task($userId);

        $canTask = $tasks->where('receive_status', ActivityEnum::RECEIVE_STATUS_CAN)->first();
        $rewards = $canTask->rewards ?? null;

        if ($rewards) {
            /**
             * @var Collection $rewards
             */
            $rewards = $rewards->where('reward_type', '<>', Coin::RELATION_TYPE)->values();
        }

        if (empty($rewards)) {
            throw new BasicException($repo->taskNoReceiveCode);
        }

        return $rewards;
    }

    /**
     * @throws BasicException
     */
    public function receive(int $userId): Collection
    {
        try {

            $rewards = $this->beforeReceive($userId);

            if (!app('redis')->set("new_user_gift_receive:$userId", 'lock', 'ex', 15, 'nx')) {
                throw new BasicException(52011);
            }

            $rewardService = new RewardService();

            $db = DB::connection('mysql');
            $activityDb = DB::connection('mysql_activity');
            $db->beginTransaction();
            $activityDb->beginTransaction();


            $rewards = $rewardService->add($rewards, $userId, '首充活动', '232');
            $rewardLog = $this->eachRewardLogData($rewards, $userId);

            Gift2022NewUserRewardLog::query()->insert($rewardLog);

            $activityDb->commit();
            $db->commit();

        } catch (ThrowableAlias $exception) {
            isset($db) && $db->rollBack();
            isset($activityDb) && $activityDb->rollBack();
            $code = $exception instanceof BasicException ? $exception->getCode() : 52013;
            $msg = $exception instanceof BasicException ? $exception->getMessage() : '';

            $this->setErrLog($exception, $userId);

            throw new BasicException($code, $msg);
        }
        return $rewards;
    }


    private function eachRewardLogData($rewards, int $uid): array
    {
        $rewards->each(function ($item) use ($uid, &$rewardLog) {
            if ($item->reward_type === Coin::RELATION_TYPE || ! empty($item->reward)) {
                $rewardLog[] = $this->makeRewardLogData($item, $uid);
            }
        });
        return $rewardLog;
    }


    private function makeRewardLogData($item, int $userId): array
    {
        if (Coin::RELATION_TYPE === $item->reward_type) {
            $totalCoin = $item->count;
        } elseif (MallProducts::RELATION_TYPE === $item->reward_type) {
            $totalCoin = 0;
        } else {
            $totalCoin = $item->count * $item->reward->price;
        }

        return [
            'setting_id'        => $item->setting_id,
            'reward_setting_id' => $item->id,
            'user_id'           => $userId,
            'reward_type'       => $item->reward_type,
            'reward_id'         => $item->reward_id,
            'count'             => $item->count,
            'total_coin'        => $totalCoin,
            'desc'              => ''
        ];
    }

    private function setErrLog($exception, $userId): void
    {
        if (! ($exception instanceof BasicException)) {
            Log::info(" 首充活动领奖失败: $userId :". $exception->getMessage());
        }
    }

}
